//
// Created by Felix on 24-4-26.
//

#include "common.hpp"
#include "AuthService.hpp"

oatpp::Object<UserResponseDto> AuthService::userResponseDtoFromModel(
        const oatpp::Object<UserModel> &model
) {
    auto dto = UserResponseDto::createShared();
    dto->userId = model->id;
    dto->username = model->username;
    dto->role = model->role;
    dto->status = model->status;
    dto->createTime = model->createTime;
    dto->updateTime = model->updateTime;
    return dto;
}

oatpp::Object<UserResponseDto> AuthService::getUserByToken(
        const oatpp::String &token
) {
    auto dbResult = iLoginLogDatabase->getActiveLoginLogByToken(token);
    OATPP_ASSERT_HTTP(dbResult->isSuccess(), Status::CODE_500, dbResult->getErrorMessage())

    auto result = dbResult->fetch<oatpp::Vector<oatpp::Vector<oatpp::Int32>>>();
    OATPP_ASSERT_HTTP(result->size() == 1, Status::CODE_401, "Unauthorized")
    auto userId = result[0][0].getValue(0);

    dbResult = iUserDatabase->getUserById(userId);
    OATPP_ASSERT_HTTP(dbResult->isSuccess(), Status::CODE_500, dbResult->getErrorMessage())

    auto user = dbResult->fetch<oatpp::Vector<oatpp::Object<UserModel>>>();
    OATPP_ASSERT_HTTP(user->size() == 1, Status::CODE_500, "Unknown Error")

    return userResponseDtoFromModel(user[0]);
}

oatpp::Object<AuthResponseDto> AuthService::signIn(
        const oatpp::Object<SignInDto> &dto
) {
    dto->password = sha256(dto->password + "gaze");
    OATPP_LOGD("password sha256: ", "%s", dto->password->c_str())
    auto dbResult = iUserDatabase->authenticateUser(dto->username, dto->password);
    OATPP_ASSERT_HTTP(dbResult->isSuccess(), Status::CODE_500, dbResult->getErrorMessage())

    auto result = dbResult->fetch<oatpp::Vector<oatpp::Vector<oatpp::Int32>>>();
    OATPP_ASSERT_HTTP(result->size() == 1, Status::CODE_401, "Unauthorized")
    auto userId = result[0][0].getValue(0);

    auto auth = AuthResponseDto::createShared();
    auth->userId = userId;

    auto token = uuidString();
    token.erase(std::remove(token.begin(), token.end(), '-'), token.end());
    auth->token = token + "_" + std::to_string(userId);

    token = uuidString();
    token.erase(std::remove(token.begin(), token.end(), '-'), token.end());
    auth->resourceToken = token + "_" + std::to_string(userId);

    token = uuidString();
    token.erase(std::remove(token.begin(), token.end(), '-'), token.end());
    auth->refreshToken = token + "_" + std::to_string(userId);

    std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
    auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
    auth->createTime = timestamp;
    auth->updateTime = timestamp;
#ifdef __APPLE__
    auth->deleteTime = 0LL;
#else
    auth->deleteTime = 0L;
#endif

    iLoginLogDatabase->createLoginLog(auth);

    return auth;
}

void AuthService::signOut(oatpp::String &token) {
    iLoginLogDatabase->updateLoginLogStatus(2, token);
}
